#include <memory>
#include "internals.hpp"

#include <set>
#include <map>
#include <vector>
#include <list>
#include <unordered_set>
#include <unordered_map>
#include <limits>

#include <iostream>

#include <assert.h>
#include <string.h>
#include <malloc.h>



struct LifeTimeTest
{
	LifeTimeTest(){
		test_enabled=true;
	}
	~LifeTimeTest(){
		test_enabled=false;
	}
	static bool test_enabled;
};
bool LifeTimeTest::test_enabled(false);

struct AllocTest
{
	AllocTest(){
		test_enabled=true;
	}
	~AllocTest(){
		test_enabled=false;
	}
	static bool test_enabled;
};
bool AllocTest::test_enabled(false);


bool stateful=true;
template <class T>
class TestAllocator
{
	public:
		enum {allocation_unit=sizeof(T)};
		TestAllocator(){}
		void* allocate(size_t num) 
		{
			void * ptr=malloc(sizeof(T)*num);
			if(ptr==NULL)throw std::bad_alloc();
			return ptr;
		}
		void deallocate(void *p, size_t num)
		{
			free(p);
		}
		size_t max_size()const
		{
			return std::numeric_limits<size_t>::max();
		}
	private:
		TestAllocator(const TestAllocator&)=delete;
};
typedef sandbox::sdk::AllocatorTemplate<int, TestAllocator> Allocator_t;



//=====================

int main(int argc, char ** argv)
{
	bool verbose(false);
	bool verdict(true);
	std::cout<<std::boolalpha;
	
	bool foo=std::is_pod<int>::value;
	
	for(int i=1; i<argc; ++i)
	{
		if(!strcmp(argv[i],"-v"))
		{
			verbose=true;
			continue;
		}
		
		if(!strcmp(argv[i], "vector"))
		{
			stateful=true;	{
				LifeTimeTest test1;	{
					std::vector<int,Allocator_t> vector;
					{
						AllocTest test2;
						vector.push_back(10);
						vector.push_back(12);
						vector.push_back(14);
						vector.pop_back();
						vector.clear();
					}
				}
			}
			if(verbose){
				std::cout<<"std::vector is ";
				if(!stateful)std::cout<<"NOT ";
				std::cout<<"stateful allocator compatible"<<std::endl;
			}
			verdict&=stateful;
			continue;
		}
		if(!strcmp(argv[i], "list"))
		{
			stateful=true;	{
				LifeTimeTest test1;	{
					std::list<int, Allocator_t> vector;
					{
						AllocTest test2;
						vector.push_back(10);
						vector.push_back(12);
						vector.push_back(14);
						vector.clear();
					}
				}
			}
			if(verbose){
				std::cout<<"std::list is ";
				if(!stateful)std::cout<<"NOT ";
				std::cout<<"stateful allocator compatible"<<std::endl;
			}
			verdict&=stateful;
			continue;
		}
		if(!strcmp(argv[i], "set"))
		{
			stateful=true;	{
				LifeTimeTest test1;	{
					std::set<int, std::less<int>, Allocator_t> vector;
					{
						AllocTest test2;
						vector.insert(10);
						vector.insert(12);
						vector.insert(14);
						vector.erase(12);
						vector.clear();
					}
				}
			}
			if(verbose){
				std::cout<<"std::set is ";
				if(!stateful)std::cout<<"NOT ";
				std::cout<<"stateful allocator compatible"<<std::endl;
			}
			verdict&=stateful;
			continue;
		}
		if(!strcmp(argv[i], "map"))
		{
			stateful=true;	{
				LifeTimeTest test1;	{
					std::map<int, bool, std::less<int>, Allocator_t> vector;
					{
						AllocTest test2;
						vector[10]=true;
						vector[12]=false;
						vector[14]=true;
						vector.erase(12);
						vector.clear();
					}
				}
			}
			if(verbose){
				std::cout<<"std::map is ";
				if(!stateful)std::cout<<"NOT ";
				std::cout<<"stateful allocator compatible"<<std::endl;
			}
			verdict&=stateful;
			continue;
		}
	/*
		if(!strcmp(argv[i], "unordered_set"))
		{
			stateful=true;	{
				LifeTimeTest test1;	{
					std::unordered_set<int, std::hash<int>, std::equal_to<int>, Allocator_t> vector;
					{
						AllocTest test2;
						vector.insert(10);
						vector.insert(12);
						vector.insert(14);
						vector.erase(12);
						vector.clear();
					}
				}
			}
			if(verbose){
				std::cout<<"std::unoredered_set is ";
				if(!stateful)std::cout<<"NOT ";
				std::cout<<"stateful allocator compatible"<<std::endl;
			}
			verdict&=stateful;
			continue;
		}			
		if(!strcmp(argv[i], "unordered_map"))
		{
			stateful=true;	{
				LifeTimeTest test1;	{
					std::unordered_map<int, bool, std::hash<int>, std::equal_to<int>, Allocator_t> vector;
					{
						AllocTest test2;
						vector[10]=true;
						vector[12]=false;
						vector[14]=true;
						vector.erase(12);
						vector.clear();
					}
				}
			}
			if(verbose){
				std::cout<<"std::unoredered_map is ";
				if(!stateful)std::cout<<"NOT ";
				std::cout<<"stateful allocator compatible"<<std::endl;
			}
			verdict&=stateful;
			continue;
		}
		*/
	}
	if(verdict==false)return 1;
	return 0;
}

